package com.nengchuan.kbms.common;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.nengchuan.config.exception.NcException;
import com.nengchuan.kbms.dfs.constant.BaseConstant;
import com.nengchuan.model.dto.PageDTO;
import com.nengchuan.model.model.NcPageInfo;
import com.nengchuan.util.MapperUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 自定义通用 pageService 实现，用于 替代 ServiceImpl
 * @param <M>
 * @param <T>
 */
public class PageServiceImpl<M extends BaseMapper<T>, T> extends ServiceImpl<M, T> implements IPageService<T> {
    @Override
    public T insert(Object object) {
        Objects.requireNonNull(object, "对象不能为空");
        Class<T> currentClass = currentModelClass();
        T instance;
        if (object.getClass() == currentClass) {
            instance = (T) object;
        } else {
            try {
                instance = currentClass.newInstance();
//                instance = MapperUtils.mapping(object, currentModelClass());
                // 忽略id属性值的拷贝，使用框架自动生成的id
                BeanUtils.copyProperties(object, instance, "id");
            } catch (Exception e) {
                throw new NcException(e);
            }
        }
        save(instance);
        return instance;
    }

    @Override
    public boolean update(Object object) {
        Objects.requireNonNull(object);
        Class<T> currentClass = currentModelClass();
        T instance = MapperUtils.mapping(object, currentClass);
        return updateById(instance);
    }

    @Override
    public <D> D getById(Long id, Class<D> clz) {
        return MapperUtils.mapping(getById(id), clz);
    }

    @Override
    public boolean remove(Serializable id) {
        Objects.requireNonNull(id);
        List<Long> idList = transIdToList(id);
        if (CollectionUtils.isEmpty(idList)) {
            return false;
        } else if (idList.size() == 1) {
            return removeById(idList.get(0));
        } else {
            return removeByIds(idList);
        }
    }

    @Override
    public <D> NcPageInfo<D> page(PageDTO pageDTO, Class<D> clz) {
        Objects.requireNonNull(pageDTO);

        long current = (pageDTO.getPageNum() != null && pageDTO.getPageNum() > 0) ? pageDTO.getPageNum() : 1;
        long size = (pageDTO.getPageSize() != null && pageDTO.getPageSize() > 0) ? pageDTO.getPageSize() : 10;
        IPage<T> page = new Page<>(current, size);
        AutoWrapper<T> wrapper = new AutoWrapper<>(pageDTO);
        wrapper.select(getFields(clz));
        return MapperUtils.mappingNcPage(page(page, wrapper), clz);
    }
    @Override
    public <D> List<D> list(Object dto, Class<D> clz) {
        Objects.requireNonNull(dto);
        QueryWrapper<T> wrapper = new AutoWrapper<>(dto);
        return MapperUtils.mappingList(list(wrapper), clz);
    }


    @Override
    public List<Long> transIdToList(Serializable id) {
        Objects.requireNonNull(id);
        if (id instanceof String) {
            String idStr = ((String) id);
            if (idStr.contains(BaseConstant.SplitLetter.COMMA)) {
                String[] idArray = StringUtils.split(idStr, BaseConstant.SplitLetter.COMMA);
                return Stream.of(idArray).map(Long::parseLong).collect(Collectors.toList());
            } else {
                try {
                    Long idLong = Long.parseLong(idStr);
                    return Lists.newArrayList(idLong);
                } catch (NumberFormatException e) {
                    throw new NcException("主键类型错误");
                }
            }
        } else if (id instanceof Long) {
            return Lists.newArrayList((Long) id);
        } else {
            throw new NcException("暂不支持的类型: " + id.getClass());
        }
    }

    /**
     * 获取目标类中能够查询的字段名数组
     * // TODO 缓存类中需要查询的字段可提升性能
     * @param clz
     * @return
     */
    private final String[] getFields(Class<?> clz) {
        String[] fields = FIELD_MAPPER.get(clz.getName());
        if (fields != null) {
            return fields;
        }
        // 得到实体类成员域
        Set<String> originFieldSet = new HashSet<>(_getFields(currentModelClass()));
        // 得到目标类成员域
        List<String> destFieldList = _getFields(clz);
        // 返回这两个类成员域中的交集
        fields = destFieldList.stream().filter(field -> originFieldSet.contains(field))
                .map(AutoWrapper::camel2Underline).toArray(String[]::new);
        FIELD_MAPPER.put(clz.getName(), fields);
        return fields;
    }

    private static final List<String> _getFields(Class<?> clz) {
        return Arrays.stream(clz.getDeclaredFields()).map(field -> field.getName()).collect(Collectors.toList());
    }

    private static final Map<String, String[]> FIELD_MAPPER = new ConcurrentHashMap<>();

}
